/*==============================================================================
**                                  LINDBOARD
**                      Proprietary - Copyright (C) 2014
**                      www.facebook.com/lindboard
**------------------------------------------------------------------------------
** Supported MCUs      : MCU STM32
** Supported Compilers : KeilC
**------------------------------------------------------------------------------
** File name         : ComM.c
**  
** Module name       : Communication Management
**
** Summary: Source file of the Communication Management module
**
**= History ===================================================================
** 00.00.01  15/1/2014  Cuong Chu
**           - Creation
** 00.00.02  29/07/2014 Cuong Chu
**           - Added COM4,COM5
**           - Port Initialize select able
**           - Correct some words
==============================================================================*/
/******************************************************************************/
/* INCLUSIONS                                                                 */
/******************************************************************************/
#include "ComM/ComM.h"
#include "Com/Com.h"
#include "ComM/ComM_Cfg.h"
#include "misc/misc.h"
/******************************************************************************/
/* DEFINITION OF CONSTANTS                                                    */
/******************************************************************************/
#define NULL_PTR ((void *)0)
/******************************************************************************/
/* DEFINITION OF TYPES                                                        */
/******************************************************************************/
typedef enum
{
  COMM_TRUE,
  COMM_FALSE
}ComM_BooleanType;
/* internal ComM message type */
typedef struct 
{
  ComM_MessageType Message;  /* payload data */
  ComM_BooleanType Empty;    /* flag of empty */
}ComM_MessageControlType;
/* buffer of COM port */
typedef struct
{
  uint8_t             Buffer[COMM_PORT_DATA_BUFFER_LEN];
  uint16_t            Pointer;
}ComM_COMBufferType;
/* ComM state machine */
typedef enum
{
  COMM_CHECK_INCOMMING_DATA,
  COMM_TRANSMIT_MSG,
}ComM_StateMachineType;
/******************************************************************************/
/* DEFINITION OF GLOBAL VARIABLE                                              */
/******************************************************************************/
/* configuration hardware parameter */
extern const ComM_PortConfigType ComM_PortConfig[COMM_NBR_COM];
/******************************************************************************/
/* DEFINITION OF LOCAL VARIABLE                                               */
/******************************************************************************/
/* Tx Message */
static          ComM_MessageControlType          iTxPayload[COMM_MAX_PAYLOAD_SIZE];
/* Rx Message */
static          ComM_MessageControlType          iRxPayload[COMM_MAX_PAYLOAD_SIZE];
/* rx buffer */
static volatile ComM_COMBufferType               iRxBuffer[COMM_NBR_COM];        
/* node id */         
static          uint32_t                         NetworkNodeID;
/* internal state processing */
static          ComM_StateMachineType            iStateSM = COMM_CHECK_INCOMMING_DATA;
/* temp buffer */
static          uint8_t                          TempBuffer[128];
/* local timer */
static volatile uint32_t                         rxSamplingTimer = 0;
/******************************************************************************/
/* DEFINITION OF MACRO                                                        */
/******************************************************************************/
/******************************************************************************/
/* DECLARATIOM OF INTERNAL FUNCTIONS                                          */
/******************************************************************************/
/*******************************************************************************
** Function name: ComM_iMessageFilter( ComM_COMBufferType     *RxBuff, 
**                                    uint16_t                MsgIndex)
** Description  : The function checks ID and validation data
** Parameter    : RxBuff - point to rx buffer check
**                MsgIndex -index of message received in buffer
**                PortID   - Port received
** Return value : None
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iMessageFilter
( 
  volatile ComM_COMBufferType     *RxBuff,
  uint16_t               MsgIndex,
  ComM_PortType          PortID
);
/*******************************************************************************
** Function name: ComM_iCheckHeaderFooter( ComM_COMBufferType     *RxBuff, 
**                                         ComM_MessageReceiveType MsgCheckType)
** Description  : The function checks header and footer of message
** Parameter    : RxBuff - point to rx buffer check
**                MsgCheckType - type u want check
** Return value : retval > 0 - first byte of message
**                retval = 0 - error message
** Remarks      : global variables used, side effects
*******************************************************************************/
static uint16_t ComM_iCheckHeaderFooter
( 
  volatile ComM_COMBufferType     *RxBuff,
  uint16_t                        MsgIdx
);
/*******************************************************************************
** Function name: ComM_iSendTxMessage( ComM_MessageType* Msg )
** Description  : The function sends COM Message
** Parameter    : Msg - point to COM message
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iSendTxMessage
( 
  ComM_MessageType* Msg
);
/*******************************************************************************
** Function name: ComM_iSendBlock( uint8_t* DataPtr, uint8_t* MsgSize)
** Description  : The function sends one block message over RS485 bus
** Parameter    : MsgPtr - point to message send
**                MsgSize - Size of message
**                ComID - Port select
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iSendBlock
( 
  uint8_t*      MsgPtr,
  uint8_t       MsgSize,
  ComM_PortType ComID
);
/*******************************************************************************
** Function name: ComM_iCopyData( uint8_t* Src, uint8_t* Dst, )
** Description  : The function copies data from source buffer to dest buffer
** Parameter    : Src - point to source buffer
**                Dst - point to dest buffer
**                Size - size of data buffer
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iCopyData
( 
  uint8_t* Src,
  uint8_t* Dst,
  uint16_t Size
);
/*******************************************************************************
** Function name: ComM_iPort1DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort1DataReceviedHandle 
( 
  uint8_t data
);
/*******************************************************************************
** Function name: ComM_iPort2DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort2DataReceviedHandle 
( 
  uint8_t data
);
/*******************************************************************************
** Function name: ComM_iPort3DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort3DataReceviedHandle 
( 
  uint8_t data
);
/*******************************************************************************
** Function name: ComM_iPort4DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort4DataReceviedHandle 
( 
  uint8_t data
);
/*******************************************************************************
** Function name: ComM_iPort5DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort5DataReceviedHandle 
( 
  uint8_t data
);
/*******************************************************************************
** Function name: ComM_iChecksum( uint8_t *DataPtr , uint8_t Size )
** Description  : The function calculates checksum of data
** Parameter    : DataPtr - point to data calculate
**                Size    - Size of data calculate
** Return value : Checksum - return checksum value 
** Remarks      : global variables used, side effects
*******************************************************************************/
static uint8_t ComM_iChecksum 
(
  uint8_t *DataPtr , 
  uint8_t Size
);
/******************************************************************************/
/* DEFINITION OF GLOBAL FUNCTIONS                                             */
/******************************************************************************/
/*******************************************************************************
** Function name: ComM_Init( uint32_t NodeID,ComM_PortType ComX )
** Description  : The function shall be init module, include hardware and software
** Parameter    : NodeID - network node ID
**                ComX - COM port name
** Return value : ComM_ReturnType 
** Remarks      : global variables used, side effects
*******************************************************************************/
ComM_ReturnType ComM_Init 
(
  uint32_t               NodeID,
  ComM_PortType          ComX
)
{
  uint16_t        LocalCounter;
  ComM_ReturnType ret = COMM_OK;
  switch(ComX)
  {
     case COMM_COM1:
          /* init hardware COM1 */
          DV_COM_Init(ComM_PortConfig[0].Port,ComM_PortConfig[0].Baudrate,&ComM_iPort1DataReceviedHandle);
          /* flush serial port 1*/
          DV_COM_WriteByte(ComM_PortConfig[0].Port,0x00);
          break;
     case COMM_COM2:
          /* init hardware COM2 */
          DV_COM_Init(ComM_PortConfig[1].Port,ComM_PortConfig[1].Baudrate,&ComM_iPort2DataReceviedHandle);
          /* flush serial port 2*/
          DV_COM_WriteByte(ComM_PortConfig[1].Port,0x00);
          break;
     case COMM_COM3:
          /* init hardware COM3 */
          DV_COM_Init(ComM_PortConfig[2].Port,ComM_PortConfig[2].Baudrate,&ComM_iPort3DataReceviedHandle);
          /* flush serial port 3*/
          DV_COM_WriteByte(ComM_PortConfig[2].Port,0x00);
          break;
     case COMM_COM4:
          /* init hardware COM4 */
          DV_COM_Init(ComM_PortConfig[3].Port,ComM_PortConfig[3].Baudrate,&ComM_iPort4DataReceviedHandle);
          /* flush serial port 4*/
          DV_COM_WriteByte(ComM_PortConfig[3].Port,0x00);
          break;
     case COMM_COM5:
          /* init hardware COM5 */
          DV_COM_Init(ComM_PortConfig[4].Port,ComM_PortConfig[4].Baudrate,&ComM_iPort5DataReceviedHandle);
          /* flush serial port 6*/
          DV_COM_WriteByte(ComM_PortConfig[4].Port,0x00);
          break;
     default:
          ret = COMM_FAILED;
          break;
        
  }
  /* keep initialize value of network node ID */
  NetworkNodeID = NodeID;
  /* set all flags of Empty rx & tx queue payload to true */
  for( LocalCounter = 0; LocalCounter < COMM_MAX_PAYLOAD_SIZE; LocalCounter++ )
  {
    /* tx queue */
    iTxPayload[LocalCounter].Empty = COMM_TRUE;
    /* rx queue */
    iRxPayload[LocalCounter].Empty = COMM_TRUE;
  }
  /* clear irxbuffer */
  for(LocalCounter = 0; LocalCounter < COMM_PORT_DATA_BUFFER_LEN; LocalCounter++)
  {
    iRxBuffer[ComX].Buffer[LocalCounter] = 0x00;
  }
  iRxBuffer[ComX].Pointer = 0;
  /* return */
  return ret;
}
/*******************************************************************************
** Function name: ComM_MainFunction( void )
** Description  : The function processes trasmit data and receive ACK/ACK
** Parameter    : None
** Return value : None
** Remarks      : global variables used, side effects
*******************************************************************************/
void ComM_MainFunction 
(
  void
)
{
  ComM_PortType    PortIndex;
  uint16_t         MessageIndex;
  uint16_t         LocalCounter;
  uint16_t         i,k;
  ComM_BooleanType keepGoing;
  switch(iStateSM)
  {
    case COMM_CHECK_INCOMMING_DATA:
      /* check message length valid on COM port */
      for(PortIndex = COMM_COM1; PortIndex < COMM_LIMIT; PortIndex++)
      {          
          /* check lenght of data received */
          if(iRxBuffer[PortIndex].Pointer >= COMM_MESSAGE_LENGTH && !rxSamplingTimer )
          {
            MessageIndex = 0;
            keepGoing = COMM_TRUE;
            /* coppy message to rx payload */
            for(i = 0;i < COMM_MAX_PAYLOAD_SIZE && keepGoing == COMM_TRUE;i++)
            {
            
              /* get message index */
              MessageIndex = ComM_iCheckHeaderFooter(&iRxBuffer[PortIndex],MessageIndex);
              /* check message valid */
              if(MessageIndex != 0xFFFF)
              {
                /* Processing Incomming Message */
                ComM_iMessageFilter( &iRxBuffer[PortIndex] , MessageIndex,PortIndex);
              }
              else
              {
                /* exit loop */
                keepGoing = COMM_FALSE;
                for (k = 0; k < iRxBuffer[0].Pointer; k++)
                {
                    iRxBuffer[0].Buffer[k] = 0;
                }
                iRxBuffer[0].Pointer = 0;
              }
            }
          }
          else
          {
            /* do nothing */
          }
      }
      /* decrement sampling timer */
      if(rxSamplingTimer)
      {
        rxSamplingTimer--;
      }
      else
      {
        /* do nothing */
      }  
      /* next to transmit state */
      iStateSM = COMM_TRANSMIT_MSG;
    break;
    case COMM_TRANSMIT_MSG:
       for(LocalCounter = 0; LocalCounter < COMM_MAX_PAYLOAD_SIZE; LocalCounter++)
       {
         /* check tx payload available data */ 
         if(iTxPayload[LocalCounter].Empty == COMM_FALSE)
         {
            ComM_iSendTxMessage(&iTxPayload[LocalCounter].Message);
            iTxPayload[LocalCounter].Empty  = COMM_TRUE;
         }         
       }
      /* next to transmit state */
      iStateSM = COMM_CHECK_INCOMMING_DATA;
    break;
    default: break;
  }
}
/*******************************************************************************
** Function name: ComM_AddMessageToQueue( ComM_MessageType* Msg )
** Description  : The function adds one COM message to Tx queue
** Parameter    : Msg - point to message send
** Return value : 
**                  COMM_OK      - if process success
**                  COMM_FAILED  - unknown error
**                  COMM_PORT_INVALID - port name is invalid
**                  COMM_OVERLOAD_TX  - TX queue is overload
** Remarks      : global variables used, side effects
*******************************************************************************/
ComM_ReturnType ComM_AddMessageToQueue
(
  ComM_MessageType* Msg
)
{
  ComM_ReturnType   retVal = COMM_FAILED;
  uint16_t          LocalCounter;
  ComM_BooleanType  keepGoing;
  /* check null pointer */
  if( Msg != NULL_PTR && Msg->Port < COMM_LIMIT)
  {
    /* check tx queue is overload */
    keepGoing = COMM_TRUE;
    LocalCounter = 0;
    /* loop check payload is available */
    while(keepGoing == COMM_TRUE && LocalCounter < COMM_MAX_PAYLOAD_SIZE)
    {
      /* check flag Empty */
      if(iTxPayload[LocalCounter].Empty == COMM_TRUE)
      {
        /* exit loop check */
        keepGoing = COMM_FALSE;
      }
      else
      {
        /* do nothing */
        LocalCounter++;
      }
    }
    /* check payload is available slot */
    if(keepGoing == COMM_FALSE)
    {
      /* set tx queue message is not empty */
      iTxPayload[LocalCounter].Empty = COMM_FALSE;
      iTxPayload[LocalCounter].Message.Port = Msg->Port;
      iTxPayload[LocalCounter].Message.SrcID = Msg->SrcID;
      iTxPayload[LocalCounter].Message.DstID = Msg->DstID;
      iTxPayload[LocalCounter].Message.Dlc = Msg->Dlc;
      iTxPayload[LocalCounter].Message.MsgID = Msg->MsgID;
      ComM_iCopyData(&Msg->Data[0],&iTxPayload[LocalCounter].Message.Data[0],COMM_DATA_LENGTH);
    }
    else
    {
      /* return overload TX queue */
      retVal = COMM_OVERLOAD_TX;
    }
  }
  else
  {
    /* do nothing */
  }
  return retVal;
}
/*******************************************************************************
** Function name: ComM_ReadMsgFromQueue( ComM_MessageType* Msg )
** Description  : The function reads one message from Rx queue
** Parameter    : Msg - point to message read
** Return value :  
**                  COMM_OK      - if process success
**                  COMM_FAILED  - unknown error
**                  COMM_PORT_INVALID - port name is invalid
**                  COMM_RX_AVAILABLE  - rx queue data ready to read
**                  COMM_RX_EMPTY     - queue empty
** Remarks      : global variables used, side effects
*******************************************************************************/
ComM_ReturnType ComM_ReadMsgFromQueue
(
  ComM_MessageType* Msg
)
{
ComM_ReturnType   retVal = COMM_FAILED;
  uint16_t          LocalCounter;
  ComM_BooleanType  keepGoing;
  /* check null pointer */
  if( Msg != NULL_PTR)
  {
    /* check rx queue is available data */
    keepGoing = COMM_TRUE;
    LocalCounter = 0;
    /* loop check payload is available */
    while(keepGoing == COMM_TRUE && LocalCounter < COMM_MAX_PAYLOAD_SIZE)
    {
      /* check flag Empty */
      if(iRxPayload[LocalCounter].Empty == COMM_FALSE)
      {
        /* exit loop check */
        keepGoing = COMM_FALSE;
      }
      else
      {
        /* do nothing */
        LocalCounter++;
      }
      
    }
    /* check payload is available slot */
    if(keepGoing == COMM_FALSE)
    {
      /* set tx queue message is not empty */
      iRxPayload[LocalCounter].Empty = COMM_TRUE;
      /* copy port name */
      Msg->Port = iRxPayload[LocalCounter].Message.Port;
      /* source ID */
      Msg->SrcID = iRxPayload[LocalCounter].Message.SrcID;
      /* dst ID */
      Msg->DstID = iRxPayload[LocalCounter].Message.DstID;
      /* data length code */
      Msg->Dlc = iRxPayload[LocalCounter].Message.Dlc;
      /* message ID */
      Msg->MsgID = iRxPayload[LocalCounter].Message.MsgID; 
      /* data */
      ComM_iCopyData(&iRxPayload[LocalCounter].Message.Data[0],&Msg->Data[0],COMM_DATA_LENGTH);
       /* check RX available data */
      keepGoing = COMM_TRUE;
      for( LocalCounter = 0; LocalCounter < COMM_MAX_PAYLOAD_SIZE && keepGoing == COMM_TRUE; LocalCounter++)
      {
        /* check flag Empty */
        if(iRxPayload[LocalCounter].Empty == COMM_FALSE)
        {
          /* exit loop check */
          keepGoing = COMM_FALSE;
          /* data is available in rx payload */
          retVal = COMM_RX_AVAILABLE;
        }
        else
        {
          /* rx payload is empty */
          retVal = COMM_OK;
        }
      }
      
    }
    else
    {
      /* return overload TX queue */
      retVal = COMM_RX_EMPTY;
    }
    
  }
  else
  {
    /* do nothing */
  }
  return retVal;
}
/*******************************************************************************
** Function name: ComM_EnableReceivePort( ComM_PortType ComName )
** Description  : The function enables receive data on port selected
** Parameter    : ComName - Name of port
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
void ComM_EnableReceivePort
(
  ComM_PortType ComName
)
{

  /* enable hardware interrupt reception */
  DV_COM_HardwareInterruptEnabled(ComM_PortConfig[ComName].Port);

}
/*******************************************************************************
** Function name: ComM_DisableReceivePort( ComM_PortType ComName )
** Description  : The function disables receive data on port selected
** Parameter    : ComID - ID of COM port
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
void ComM_DisableReceivePort
(
  ComM_PortType ComID
)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  /* disable hardware interrupt reception */
  DV_COM_HardwareInterruptDisabled(ComM_PortConfig[ComID].Port);
    /* enable interrupt channel */
	NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
  NVIC_Init( &NVIC_InitStructure );
}
/******************************************************************************/
/* DEFINITION OF INTERNAL FUNCTIONS                                           */
/******************************************************************************/
/*******************************************************************************
** Function name: ComM_iPort1DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort1DataReceviedHandle 
( 
  uint8_t data
)
{
  /* check data */
  if(iRxBuffer[0].Pointer < COMM_PORT_DATA_BUFFER_LEN)
  {
    /* reset sampling timer */
    rxSamplingTimer = COMM_SAMPLING_TIME;
    /* copy data to buffer and increment pointer */
    iRxBuffer[0].Buffer[iRxBuffer[0].Pointer++] = data;
  }
  else
  {
    /* reset counter */
    iRxBuffer[0].Pointer = 0;
  }
}
/*******************************************************************************
** Function name: ComM_iPort2DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort2DataReceviedHandle 
( 
  uint8_t data
)
{
  /* check data */
  if(iRxBuffer[1].Pointer < COMM_PORT_DATA_BUFFER_LEN)
  {
    /* reset sampling timer */
    rxSamplingTimer = COMM_SAMPLING_TIME;
    /* copy data to buffer and increment pointer */
    iRxBuffer[1].Buffer[iRxBuffer[1].Pointer++] = data;
  }
  else
  {
    /* reset counter */
    iRxBuffer[1].Pointer = 0;
  }
}
/*******************************************************************************
** Function name: ComM_iPort3DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort3DataReceviedHandle 
( 
  uint8_t data
)
{
  /* check data */
  if(iRxBuffer[2].Pointer < COMM_PORT_DATA_BUFFER_LEN)
  {
    /* reset sampling timer */
    rxSamplingTimer = COMM_SAMPLING_TIME;
    /* copy data to buffer and increment pointer */
    iRxBuffer[2].Buffer[iRxBuffer[2].Pointer++] = data;
  }
  else
  {
    /* reset counter */
    iRxBuffer[2].Pointer = 0;
  }
}
/*******************************************************************************
** Function name: ComM_iPort4DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort4DataReceviedHandle 
( 
  uint8_t data
)
{
  /* check data */
  if(iRxBuffer[3].Pointer < COMM_PORT_DATA_BUFFER_LEN)
  {
    /* reset sampling timer */
    rxSamplingTimer = COMM_SAMPLING_TIME;
    /* copy data to buffer and increment pointer */
    iRxBuffer[3].Buffer[iRxBuffer[3].Pointer++] = data;
  }
  else
  {
    /* reset counter */
    iRxBuffer[3].Pointer = 0;
  }
}
/*******************************************************************************
** Function name: ComM_iPort5DataReceviedHandle( uint8_t data )
** Description  : The function handles data recevied from hardware
** Parameter    : data - data recevied
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iPort5DataReceviedHandle 
( 
  uint8_t data
)
{
  /* check data */
  if(iRxBuffer[4].Pointer < COMM_PORT_DATA_BUFFER_LEN)
  {
    /* reset sampling timer */
    rxSamplingTimer = COMM_SAMPLING_TIME;
    /* copy data to buffer and increment pointer */
    iRxBuffer[4].Buffer[iRxBuffer[4].Pointer++] = data;
  }
  else
  {
    /* reset counter */
    iRxBuffer[4].Pointer = 0;
  }
}
/*******************************************************************************
** Function name: ComM_iChecksum( uint8_t *DataPtr , uint8_t Size )
** Description  : The function calculates checksum of data
** Parameter    : DataPtr - point to data calculate
**                Size    - Size of data calculate
** Return value : Checksum - return checksum value 
** Remarks      : global variables used, side effects
*******************************************************************************/
static uint8_t ComM_iChecksum 
(
  uint8_t *DataPtr , 
  uint8_t Size
)
{
  uint8_t retVal = 0x00;
  uint8_t i;
  /* check pointer is null */
  if(NULL_PTR != DataPtr )
  {
    /* loop calculate */
    for(i = 0; i< Size ;i++)
    {
      retVal ^= *DataPtr++;
    }
  }
  else
  {
    /* do nothing */
  }
  return retVal;
}
/*******************************************************************************
** Function name: ComM_iCopyData( uint8_t* Src, uint8_t* Dst, )
** Description  : The function copies data from source buffer to dest buffer
** Parameter    : Src - point to source buffer
**                Dst - point to dest buffer
**                Size - size of data buffer
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iCopyData
( 
  uint8_t* Src,
  uint8_t* Dst,
  uint16_t Size
)
{
  while(Size)
  {
    *Dst++ = *Src++;
    /* decrement size */
    Size--;
  }
}
/*******************************************************************************
** Function name: ComM_iSendBlock( uint8_t* DataPtr, uint8_t* MsgSize)
** Description  : The function sends one block message over RS485 bus
** Parameter    : MsgPtr - point to message send
**                MsgSize - Size of message
**                ComID - Port select
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iSendBlock
( 
  uint8_t*      MsgPtr,
  uint8_t       MsgSize,
  ComM_PortType ComID
)
{
  /* check null ptr */
  if(MsgPtr != NULL_PTR )
  {
    while(MsgSize)
    {
      /* send byte to hardware layer */
      DV_COM_WriteByte(ComM_PortConfig[ComID].Port,*MsgPtr);
      /* incerment pointer */
      MsgPtr++;
      /* decrement size */
      MsgSize--;
    }
  }
  else
  {
    /* do nothing */
  }
}
/*******************************************************************************
** Function name: ComM_iSendTxMessage( ComM_MessageType* Msg )
** Description  : The function sends COM Message
** Parameter    : Msg - point to COM message
** Return value : None 
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iSendTxMessage
( 
  ComM_MessageType* Msg
)
{
  uint8_t i;
  /* check null ptr */
  if(Msg != NULL_PTR)
  {
    /* packet header feild */
    TempBuffer[0] = (uint8_t)(COMM_MESSAGE_HEADER & 0x00FF);
    TempBuffer[1] = (uint8_t)((COMM_MESSAGE_HEADER >> 8) & 0x00FF);
    /* packet source ID feild */
    TempBuffer[2] = (uint8_t)(Msg->SrcID  & 255UL);
    TempBuffer[3] = (uint8_t)((Msg->SrcID >> 8) & 255UL);
    TempBuffer[4] = (uint8_t)((Msg->SrcID >> 16) & 255UL);
    TempBuffer[5] = (uint8_t)((Msg->SrcID >> 24) & 255UL);
    /* packet dest ID */
    TempBuffer[6] = (uint8_t)(Msg->DstID  & 255UL);
    TempBuffer[7] = (uint8_t)((Msg->DstID >> 8) & 255UL);
    TempBuffer[8] = (uint8_t)((Msg->DstID >> 16) & 255UL);
    TempBuffer[9] = (uint8_t)((Msg->DstID >> 24) & 255UL);
    /* packet msg ID */
    TempBuffer[10] = (uint8_t)(Msg->MsgID);
    /* data length */
    TempBuffer[11] = Msg->Dlc;
    /* packet data */
    ComM_iCopyData(Msg->Data,&TempBuffer[12],Msg->Dlc);
    /* padding byte */
    if(Msg->Dlc < COMM_DATA_LENGTH)
    {
      i = 12 + Msg->Dlc;
      /* add padding byte */
      while( i < (12 + COMM_DATA_LENGTH ) )
      {
        TempBuffer[i++] = COMM_MESSAGE_PADDING_BYTE;
      }
    }
    else
    {
      /* do nothing */
    }
    /* packet feild checksum */
    TempBuffer[12+COMM_DATA_LENGTH] = ComM_iChecksum(Msg->Data,Msg->Dlc);
    /* packet footer feild */
    TempBuffer[13+COMM_DATA_LENGTH] = (uint8_t)(COMM_MESSAGE_FOOTER & 0x00FF);
    TempBuffer[14+COMM_DATA_LENGTH] = (uint8_t)((COMM_MESSAGE_FOOTER >> 8) & 0x00FF);
    /* send message */
    ComM_iSendBlock(TempBuffer,COMM_MESSAGE_LENGTH,Msg->Port);
  }
  else
  {
    /* do nothing */
  }
}
/*******************************************************************************
** Function name: ComM_iCheckHeaderFooter( ComM_COMBufferType     *RxBuff, 
**                                         ComM_MessageReceiveType MsgCheckType)
** Description  : The function checks header and footer of message
** Parameter    : RxBuff - point to rx buffer check
**                MsgCheckType - type u want check
** Return value : retval > 0 - first byte of message
**                retval = 0 - error message
** Remarks      : global variables used, side effects
*******************************************************************************/
static uint16_t ComM_iCheckHeaderFooter
( 
  volatile ComM_COMBufferType     *RxBuff,
  uint16_t                        MsgIdx
)
{
  ComM_BooleanType keepGoing = COMM_TRUE;
  uint16_t         FooterRead;
  uint16_t         HeaderRead;
  uint16_t         HeaderIndex;
  uint16_t         FooterIndex;
  ComM_BooleanType isHeader = COMM_FALSE;
  ComM_BooleanType isFooter = COMM_FALSE;
  uint16_t         i;
  uint16_t         retVal = 0xFFFF;
  /* check null ptr */
  if(RxBuff != NULL_PTR)
  {
    /* search header */
    for(i = 0; i < RxBuff->Pointer && i < COMM_PORT_DATA_BUFFER_LEN && keepGoing == COMM_TRUE;i++)
    {
      /* check header was read */
      if(isHeader == COMM_FALSE)
      {
        /* check first byte of header */
        HeaderRead = *((uint16_t*)&RxBuff->Buffer[i]);
        if( HeaderRead == COMM_MESSAGE_HEADER)
        {
          HeaderIndex = i;
          /* header valid */
          isHeader = COMM_TRUE;
        }
        else
        {
          /* do nothing */
        }
      }
      else
      {
         /* do nothing */
      } 
      /* check footer if header was read*/
      if(isFooter == COMM_FALSE && isHeader == COMM_TRUE && (i - HeaderIndex) == 21)
      {
        /* check first byte of header */
        FooterRead = *((uint16_t*)(&RxBuff->Buffer[i]));
        if( FooterRead == COMM_MESSAGE_FOOTER)
        {
          FooterIndex = i;
          /* exit check */
          keepGoing = COMM_FALSE;
          /* footer valid */
          isFooter = COMM_TRUE;
        }
        else
        {
          /* do nothing */
        }
      }
      else
      {
        /* do nothing */
      }
    }
    /* check header valid and footer valid */
    if( FooterIndex - HeaderIndex == 21)
    {
      retVal = HeaderIndex;
    }
    /* search again if data in buffer has two or more header format */
    else if(FooterIndex - HeaderIndex < 21 || FooterIndex - HeaderIndex > 21)
    {
      keepGoing = COMM_TRUE;
      isHeader = COMM_FALSE;
      isFooter = COMM_FALSE;
      /* search header */
      for(i = HeaderIndex + 2; i < RxBuff->Pointer && i < COMM_PORT_DATA_BUFFER_LEN && keepGoing == COMM_TRUE;i++)
      {
        /* check header was read */
        if(isHeader == COMM_FALSE)
        {
          /* check first byte of header */
          HeaderRead = *((uint16_t*)&RxBuff->Buffer[i]);
          if( HeaderRead == COMM_MESSAGE_HEADER)
          {
            HeaderIndex = i;
            /* header valid */
            isHeader = COMM_TRUE;
          }
          else
          {
            /* do nothing */
          }
        }
        else
        {
           /* do nothing */
        } 
        /* check footer if header was read*/
        if(isFooter == COMM_FALSE && isHeader == COMM_TRUE && (i - HeaderIndex ) == 21)
        {
          /* check first byte of header */
          FooterRead = *((uint16_t*)(&RxBuff->Buffer[i]));
          if( FooterRead == COMM_MESSAGE_FOOTER)
          {
            FooterIndex = i;
            /* exit check */
            keepGoing = COMM_FALSE;
            /* footer valid */
            isFooter = COMM_TRUE;
          }
          else
          {
            /* do nothing */
          }
        }
        else
        {
          /* do nothing */
        }
      }
      /* check header valid and footer valid */
      if( FooterIndex - HeaderIndex == 21)
      {
        retVal = HeaderIndex;
      }
      else
      {
        /* clear buffer */
        for (i =  MsgIdx ; i < FooterIndex + 1; i++)
        {
          iRxBuffer[0].Buffer[i] = 0x00;
        }
      }
    }
    else
    {
      /* clear buffer */
      for (i =  MsgIdx ; i < FooterIndex + 1; i++)
      {
        iRxBuffer[0].Buffer[i] = 0x00;
      }
    }
  }
  else
  {
    /* do nothing */
  }
  return retVal;
}
/*******************************************************************************
** Function name: ComM_iMessageFilter( ComM_COMBufferType     *RxBuff, 
**                                    uint16_t                MsgIndex)
** Description  : The function checks ID and validation data
** Parameter    : RxBuff - point to rx buffer check
**                MsgIndex -index of message received in buffer
** Return value : None
** Remarks      : global variables used, side effects
*******************************************************************************/
static void ComM_iMessageFilter
( 
  volatile ComM_COMBufferType     *RxBuff,
  uint16_t               MsgIndex,
  ComM_PortType          PortID
)
{
  uint32_t Temp;
  uint16_t i;
  ComM_BooleanType keepGoing;
  /* check null pointer */
  if(RxBuff != NULL_PTR)
  {
    /* get dest ID feild */
    Temp = *((uint32_t*)&RxBuff->Buffer[MsgIndex+6]);
    /* check ID valid */
    if(Temp == NetworkNodeID)
    {
      keepGoing = COMM_TRUE;
      /* coppy message to rx payload */
      for(i = 0;i < COMM_MAX_PAYLOAD_SIZE && keepGoing == COMM_TRUE;i++)
      {
        /* check payload is empty */
        if(iRxPayload[i].Empty == COMM_TRUE)
        {
          /* copy data to payload */
          /* port ID */
          iRxPayload[i].Message.Port = PortID;
          /* source ID */
          iRxPayload[i].Message.SrcID = *((uint32_t*)&RxBuff->Buffer[MsgIndex+2]);
          /* dest ID */
          iRxPayload[i].Message.DstID = *((uint32_t*)&RxBuff->Buffer[MsgIndex+6]);
          /* message ID */
          iRxPayload[i].Message.MsgID = RxBuff->Buffer[MsgIndex+10];
          /* data length code */
          iRxPayload[i].Message.Dlc = RxBuff->Buffer[MsgIndex+11];
          /* data */
          ComM_iCopyData((uint8_t*)&RxBuff->Buffer[MsgIndex+12],iRxPayload[i].Message.Data,COMM_DATA_LENGTH);
          /* received check sum */
          iRxPayload[i].Message.rxChksum = RxBuff->Buffer[MsgIndex+20];
          /* set not empty */
          iRxPayload[i].Empty = COMM_FALSE;
          /* exit loop check */
          keepGoing = COMM_FALSE;
          
        }
        else
        {
          /* do nothing */
        }        
      }
      /* clear message in buffer */
      for (i = MsgIndex; i < MsgIndex + COMM_MESSAGE_LENGTH ; i++)
      {
          RxBuff->Buffer[i] = 0x00;
      }
    }
    else
    {
        /* clear header of buffer */
        for (i = MsgIndex; i < MsgIndex + 2; i++)
        {
            RxBuff->Buffer[i] = 0x00;
        }
    }
  }
  else
  {
    /* do nothing */
  }
}
/******************************************************************************/
/*                              End Of File                                   */
/******************************************************************************/
